// ============================================================================
//
// Copyright (C) 2006-2007 Dengues
//
// Google Group: http://groups.google.com/group/dengues
// QQ Group: 24885404
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
// ============================================================================
package org.dengues.designer.core.components;

import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.ResourceBundle;

import org.apache.log4j.Logger;
import org.dengues.commons.ui.swt.colorstyledtext.EModeLanguage;
import org.dengues.core.ExceptionOperation;
import org.dengues.core.components.EGlobalComponentNames;
import org.dengues.core.components.IComponentsFactory;
import org.dengues.core.components.IXMLComponent;
import org.dengues.core.dbs.AbstractStandardComponent;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.FileLocator;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Platform;
import org.osgi.framework.Bundle;

/**
 * Qiang.Zhang.Adolf@gmail.com class global comment. Detailled comment <br/>
 * 
 * $Id: Dengues.epf 1 2006-09-29 17:06:40Z qiang.zhang $
 * 
 */
public class ComponentsFactory implements IComponentsFactory {

    private static Logger logger = Logger.getLogger(ComponentsFactory.class);

    private List<IXMLComponent> components = null;

    /**
     */
    public ComponentsFactory() {
    }

    public void init() {
        long startTime = System.currentTimeMillis();
        components = new ArrayList<IXMLComponent>();

        // 1. Load system components:
        loadComponentsFromFolder(COMPONENTS_LOCATION, COMPONENTS_INNER_FOLDER, null);

        // 2.Load standrad components from extension point:
        IConfigurationElement[] cef = Platform.getExtensionRegistry().getConfigurationElementsFor(COMPONENT_EXTENSION);
        for (IConfigurationElement ce : cef) {
            String attribute = ce.getAttribute(COMPONENT_ATTRI_FOLDER);
            AbstractStandardComponent cee;
            try {
                cee = (AbstractStandardComponent) ce.createExecutableExtension(COMPONENT_ATTRI_CLASS);
                loadComponentsFromFolder(ce.getNamespaceIdentifier(), attribute, cee.getClass().getClassLoader());
            } catch (CoreException e) {
                ExceptionOperation.operate(e);
            }
        }
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "loadComponentsFromFolder".
     * 
     * @param pid
     * @param innerFolder
     * @param classLoader
     */
    private void loadComponentsFromFolder(String pid, String innerFolder, ClassLoader classLoader) {
        File componentsLocation = getComponentsLocation(pid, innerFolder);
        File[] childDirectories;
        FileFilter fileFilter = new FileFilter() {

            /*
             * (non-Javadoc)
             * 
             * @see java.io.FileFilter#accept(java.io.File)
             */
            public boolean accept(File file) {
                return file.isDirectory() && file.getName().charAt(0) != '.'
                        && !file.getName().equals(COMPONENTS_USER_INNER_FOLDER);
            }

        };
        childDirectories = componentsLocation.listFiles(fileFilter);
        if (childDirectories != null) {
            for (File currentFolder : childDirectories) {
                try {
                    File xmlMainFile = new File(currentFolder, ComponentFilesNaming.getInstance().getMainXMLFileName(
                            currentFolder.getName(), getCodeLanguageSuffix()));
                    EmfXMLComponent currentComp = new EmfXMLComponent(xmlMainFile, innerFolder);
                    currentComp.setPluginId(pid);
                    if (!components.contains(currentComp)) {
                        ResourceBundle crb = getComponentResourceBundle(currentComp, classLoader);
                        currentComp.setResourceBundle(crb);
                        loadIcons(currentFolder, currentComp);
                        components.add(currentComp);
                        EGlobalComponentNames.checkComponentNames(currentComp.getName());
                    }
                } catch (Exception e) {
                    logger.error("loadComponentsFromFolder: ", e); //$NON-NLS-1$
                }
            }
        }
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "loadIcons".
     * 
     * @param currentFolder
     * @param currentComp
     */
    private void loadIcons(File currentFolder, EmfXMLComponent currentComp) {
        ComponentIconsLoading loading = new ComponentIconsLoading(currentFolder);
        currentComp.setIcon16(loading.getImage16());
        currentComp.setIcon24(loading.getImage24());
        currentComp.setIcon32(loading.getImage32());
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com ComponentsFactory class global comment. Detailled comment <br/>
     * 
     * $Id: Dengues.epf Qiang.Zhang.Adolf@gmail.com 2008-5-9 qiang.zhang $
     * 
     */
    private static class ResClassLoader extends ClassLoader {

        ResClassLoader(ClassLoader parent) {
            super(parent);
        }
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "getComponentResourceBundle".
     * 
     * @param currentComp
     * @param classLoader
     * @return
     */
    private ResourceBundle getComponentResourceBundle(EmfXMLComponent currentComp, ClassLoader classLoader) {
        String label = ComponentFilesNaming.getInstance().getBundleName(currentComp.getPathSource(), currentComp.getName());
        if (classLoader == null) {
            classLoader = getClass().getClassLoader();
        }
        ResourceBundle bundle = ResourceBundle.getBundle(label, Locale.getDefault(), new ResClassLoader(classLoader));
        return bundle;
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "getCodeLanguageSuffix".
     * 
     * @return
     */
    private String getCodeLanguageSuffix() {
        return EModeLanguage.JAVA.getLanguageMode();
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "getComponentsLocation".
     * 
     * @param pid
     * @param innerFolder
     * @return
     */
    private File getComponentsLocation(String pid, String innerFolder) {
        Bundle bundle = Platform.getBundle(pid);
        URL url = null;
        try {
            URL componentURL = FileLocator.find(bundle, new Path(innerFolder), null);
            url = FileLocator.toFileURL(componentURL);
        } catch (IOException e) {
            logger.error("Get Components Location is Error: ", e); //$NON-NLS-1$
        }
        File dir = new File(url.getPath());
        return dir;
    }

    public List<IXMLComponent> getComponents() {
        if (components == null) {
            init();
        }
        return this.components;
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.dengues.core.components.IComponentsFactory#getComponent(java.lang.String)
     */
    public IXMLComponent getComponent(String compName) {
        if (components == null) {
            init();
        }
        for (IXMLComponent component : components) {
            if (component.getName().equals(compName)) {
                return component;
            }

        }
        return null;
    }
}
